package com.opennetexam.manager.bussinessservice;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.opennetexam.manager.common.PageBean;
import com.opennetexam.manager.mapper.*;
import com.opennetexam.manager.common.CommonFunction;
import com.opennetexam.manager.common.OperationResult;
import com.opennetexam.manager.databasemodel.*;
import com.opennetexam.manager.dto.*;
import com.opennetexam.manager.enums.*;
import com.opennetexam.manager.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.regex.Pattern;

/**
 * @author 奶茶
 * Created on 2017/11/15.
 */
@Service("examMonitorService")
@Transactional(rollbackFor = RuntimeException.class)
public class ExamMonitorService {


    @Autowired
    private ExamMoniterMapper examMoniterMapper;
    @Autowired
    private ExamSubjectMapper examSubjectMapper;
    @Autowired
    private ExamineeArrangeMapper examineeArrangeMapper;
    @Autowired
    private ExamineeMapper examineeMapper;
    @Autowired
    private ExamPlanInfoMapper examPlanInfoMapper;
    @Autowired
    private ExamingMoniterLogMapper examingMoniterLogMapper;
    @Autowired
    private ExamScenesMapper examScenesMapper;
    @Autowired
    private ExamRoomMapper examRoomMapper;
    @Autowired
    private ExamComputerMapper examComputerMapper;

    //公共变量
    private static String arrangeKey = "arrange";
    private static String subjectKey = "subject";

    /**
     * 获取未结束的考试计划列表
     * @param siteId 考点ID
     * @param planType 考试计划类别
     * @return
     */
    public List<ExamPlanInfoTime> notOverExamPlanInfo(String siteId, Short planType){

        //统考模式下的考场信息
        List<ExamPlanInfoTime> unifiedExamList = examMoniterMapper.findUnifiedExamList(siteId, planType, ExamMode.unifiedExam.getPrefix(), ExamPlanSysState.TestPaperCreated.getPrefix());
        //随考模式下的考场信息
        List<ExamPlanInfoTime> freeExamList = examMoniterMapper.findFreeExamList(siteId, planType, ExamMode.freeExam.getPrefix(), ExamPlanSysState.TestPaperCreated.getPrefix());

        //将随考与统考的信息对接
        unifiedExamList.addAll(freeExamList);

        List<ExamPlanInfoTime> list = new ArrayList<>();
        if(!unifiedExamList.isEmpty()){
            for (ExamPlanInfoTime item:unifiedExamList) {
                List<ExamSubject> examSubjects = examSubjectMapper.examSubjectMoniter(item.getAppID(), item.getExamPlanInfoID(), item.getExamSceneID(), item.getExamRoomID());

                Map<String, Object> map = CommonFunction.maxTimeLimitsAndSubjectName(examSubjects);
                item.setTimeLimits((Integer) map.get("maxTime"));
                item.setSubjectName(String.valueOf(map.get("subjectName")));

                //获取最晚结束时间
                long time = DateUtil.convertStringToDate(item.getEndtime()).getTime();
                item.setEndtime(DateUtil.convertMillisecondToDateString(time));

                //与当前时间比较获取未结束的信息
                if(DateUtil.convertStringToDate(item.getEndtime()).getTime() >= System.currentTimeMillis()){
                    list.add(item);
                }
            }
        }
        return list;
    }

    /**
     * 根据考场计划，考场，场次，科目，考生状态获取考生考试情况列表
     * @param requestBody
     * @return
     */
    public Object examCaseList(ExamAdminInfoDTO adminInfo, Map<String, Object> requestBody){
        String examCardNo = null;
        String examineeName = null;
        String appId = adminInfo.getAppID();
        String siteId = adminInfo.getExamSiteID();
        String planId = (String) requestBody.get(ParameterKey.PLANID.getDisplay());
        String roomId = (String) requestBody.get(ParameterKey.ROOMID.getDisplay());
        Integer sysState = (Integer) requestBody.get("statusId");
        String subjectId = (String) requestBody.get("subjectId");
        String sceneId = (String) requestBody.get(ParameterKey.SCENEID.getDisplay());
        Boolean anImport = Boolean.valueOf(requestBody.get("anImport").toString());
        int currentPage = Integer.valueOf(requestBody.get("currentPage").toString());
        int pageSize = Integer.valueOf(requestBody.get("pageSize").toString());

        String parameter = (String) requestBody.get("parameter");

        Pattern compile = Pattern.compile("^[\\u4e00-\\u9fa5]+$");
        if(parameter != null){
            if(compile.matcher(parameter.trim()).matches()){
                examineeName = parameter.trim();
            }else{
                examCardNo = parameter.trim();
            }
        }

        // 考试计划不能为空
        if (planId.isEmpty()){
            return null;
        }

        // 考场不能为空
        if (roomId.isEmpty()){return null;}

        List<ExaminerMoniterDTO> examCaseList = new ArrayList<>();
        //根据条件过滤
        if(!anImport){
            PageHelper.startPage(currentPage,pageSize,true);
            examCaseList = (List<ExaminerMoniterDTO>)findExamCaseList(appId, siteId, planId, roomId, sysState, subjectId, sceneId, examCardNo, examineeName,anImport);
            PageUtils.getPageByPagedList(examCaseList, currentPage, pageSize, ((Page) examCaseList).getTotal());
            long total = ((Page) examCaseList).getTotal();
            PageBean<ExaminerMoniterDTO> pageBean = new PageBean<ExaminerMoniterDTO>(currentPage, pageSize,Long.valueOf(total).intValue());
            pageBean.setItems(examCaseList);
            return pageBean;
        }else{
            List<Map<String,Object>> mapList = (List<Map<String,Object>>)findExamCaseList(appId, siteId, planId, roomId, sysState, subjectId, sceneId, examCardNo, examineeName,anImport);
            if(ListUtil.isEmpty(mapList)){
                return null;
            }else{
                String title = mapList.get(0).get("批次") + "_" + mapList.get(0).get("科目");
                String randomFilePath = ExamSitePath.rootPath + "/" +System.currentTimeMillis() + ".xlsx";
                ImportUtil.importExcel(mapList,randomFilePath,title);
                return randomFilePath;
            }
        }
    }

    private Object findExamCaseList(String appId, String siteId, String planId, String roomId, Integer sysState, String subjectId, String sceneId, String examCardNo, String examineeName,Boolean anImport){
        List<ExaminerMoniterDTO> examCaseList = examMoniterMapper.findExamCaseList(appId, siteId, planId, roomId, sysState, subjectId, sceneId, examCardNo, examineeName);
        List<Map<String,Object>> mapList = new ArrayList<>();
        if(!examCaseList.isEmpty()){
            examCaseList.forEach(examinerMoniterDTO -> {
                examinerMoniterDTO.setFaceCompareFailCount(examMoniterMapper.getFaceCompareFailCount(examinerMoniterDTO.getExamineeArrangeID().toString()));
                if(anImport){
                    Map<String,Object> map = new TreeMap<>();
                    map.put("批次",examinerMoniterDTO.getExamPlanName());
                    map.put("科目",examinerMoniterDTO.getExamSubjectName());
                    map.put("准考证号",examinerMoniterDTO.getExamCardNo());
                    map.put("姓名",examinerMoniterDTO.getExamineeName());
                    //map.put("考试状态",examinerMoniterDTO.getExamStatus());
                    map.put("实际开考时间",examinerMoniterDTO.getRelBeginTime());
                    map.put("预警状态",examinerMoniterDTO.getFaceCompareFailCount() > 0 ? "异常":"正常");
                    mapList.add(map);
                }
            });
        }
        if(anImport){
            return mapList;
        }else{
            return examCaseList;

        }
    }

    /**
     * 保存单个考生强制交卷信息
     * @param arrangeId 编排ID
     * @return
     */
    public OperationResult mandatoryInfo(String arrangeId){
        // 如果编排ID不存在，则返回null
        if (StringUtils.isEmpty(arrangeId)) {
            return new OperationResult(OperationResultType.Error, "ID不能为空");
        }

        //根据编排ID找到考试考试过程监控表中对应信息
        ExamingMonitor monitor = examMoniterMapper.getExamMoniterBySomeWhereAndArrangId(arrangeId);

        if (monitor == null) {
            return new OperationResult(OperationResultType.Error, "监考数据未找到！");
        }
        // 判断学生是否应已交卷
        if (!monitor.getSysState().equals(ExamManagerState.BeingNotSubmit.getPrefix().shortValue())) {
            return new OperationResult(OperationResultType.Error, "该考生不是 已开考未交卷 状态，不能进行强制交卷！");
        }

        monitor.setSysState(Short.valueOf(ExamManagerState.Submited.getPrefix().toString()));
        monitor.setSubmitType(Short.valueOf(TestPaperSubmitType.CompellentSubmit.getPrefix().toString()));
        monitor.setExamEndTime(DateUtil.convertDateToString(new Date()));

        examMoniterMapper.updateTime(monitor);
        return new OperationResult(OperationResultType.Success, "强制交卷成功", monitor);
    }

    /**
     * 保存考生违纪信息
     * @param arrangeId 考试编排ID
     * @param disciplineId 违纪类型
     * @return
     */
    public OperationResult disciplineExamInfo(String arrangeId, Short disciplineId){
        // 基础参数检查
        PublicHelper.checkArgument(arrangeId, "ExamineeArrangeID");
        PublicHelper.checkArgument(disciplineId, "DisciplineID");

        // 检查参数完整性
        if (StringUtils.isEmpty(arrangeId) || disciplineId == 0) {
            return new OperationResult(OperationResultType.ParamError, "参数传递不完整");
        }

        //根据考生编排表ID过滤
        ExamineeArrange examineeArrange = examineeArrangeMapper.getExamineeArrangeById(arrangeId);

        //根据考试编排表的关联查询考试过程监控表
        ExamingMonitor monitor = examMoniterMapper.getExamMoniterBySomeWhere(examineeArrange.getAppID(), examineeArrange.getExamPlanInfoID(), examineeArrange.getExamRoomID(), examineeArrange.getExamSceneID(), examineeArrange.getExamSubjectID(), examineeArrange.getExamineeID());
        if(monitor != null){
            //修改考试监控表中的数据
            monitor.setIfDeregulation(disciplineId);
            examMoniterMapper.updateTime(monitor);
            //作弊类型
            DeregulationItem reason = examMoniterMapper.getDeregulationItemById(disciplineId);
            String discipline = "";
            //判断考试类型
            Integer examMode = examPlanInfoMapper.findExamPlanInfoFirst(examineeArrange.getExamPlanInfoID()).getExamMode();
            if(examMode.equals(ExamMode.freeExam.getPrefix())){
                discipline = "考试进行中作弊";
            }else{
                //开考多少时间
                long minu = System.currentTimeMillis() - DateUtil.convertStringToDate(monitor.getExamStartTime()).getTime();
                discipline = String.format("考试进行%s分钟标记作弊",minu/(1000*60));
            }
            //添加一条日志
            ExamingMonitorLog examingMonitorLog = new ExamingMonitorLog();
            examingMonitorLog.setReason(reason.getDeregulationItem());
            examingMonitorLog.setMemo(discipline);
            examingMonitorLog.setExamineeArrangeID(arrangeId);
            examingMonitorLog.setTypeID(MonitorLogType.Deregulation.getPrefix());
            examingMoniterLogMapper.insertLog(examingMonitorLog);
            return new OperationResult(OperationResultType.Success);
        }else{
            // 考试编排ID为空
            return new OperationResult(OperationResultType.QueryNull, "用户不存在");
        }
    }


    /**
     * 根据考生编号获取考生信息
     * @param examineeId 考生编号
     * @param appId 主办方ID
     * @param planId 考试计划ID
     * @return
     */
    public ExamStudentInfoViewModel getStuInfo(String examineeId, String appId, String planId,String subjectId){
        ExamStudentInfoViewModel info = examMoniterMapper.getExamStudentInfoViewModelBySomeWhere(examineeId, appId, planId);
        ExamineeArrange examineeArrange = examineeArrangeMapper.getExamineeArrange(planId, appId, examineeId,subjectId);
        info.setExamSceneName(examScenesMapper.getExamScenesBySomeWhere(examineeArrange.getAppID(), examineeArrange.getExamPlanInfoID(), examineeArrange.getExamSceneID()).getExamSceneName());
        info.setExamRoomName(examRoomMapper.getExamRoomBySomeWhere(examineeArrange.getAppID(),examineeArrange.getExamRoomID()).getExamRoomName());
        info.setExamSubjectName(examSubjectMapper.examSubjectFirstOrDefault(examineeArrange.getAppID(),examineeArrange.getExamPlanInfoID(),examineeArrange.getExamSubjectID()).getSubjectName());
        info.setSeatNo(examineeArrange.getSeatNo() == null ? 0:examineeArrange.getSeatNo());
        ExamComputer examComputer = examComputerMapper.getExamComputerBySomeWhere(examineeArrange.getExamRoomID(), examineeArrange.getSeatNo());
        info.setComputerIP(examComputer == null ? "":examComputer.getComputerIP());
        info.setPhoto(examineeMapper.findExamineeInfo(examineeId).getPhotoResource());
        return info;
    }

    /**
     * 获取违纪类型的下拉列表
     * @return
     */
    public List<DeregulationItem> deregulationItemList(){
        return examMoniterMapper.findAll();
    }

    public OperationResult freeSignInTemple(List<ExamingMonitor> examingeMonitorsList, String idCardReason){
        //当天开始时间
        long dateStartTime = DateUtil.getDateStartTime(System.currentTimeMillis());
        //当天结束时间
        long dateEndTime = DateUtil.getDateEndTime(System.currentTimeMillis());

        // 随考每天允许签到一次
        //查询是否已签到
        //1，签到状态iDCardResult ！= 0
        //2，开考时间 >=  当天开始时间  && 开考时间 <  当天结束时间
        boolean signInStatus = false;
        for (ExamingMonitor examingMonitor : examingeMonitorsList) {
            Integer idCardResult = examingMonitor.getiDCardResult();
            long idCardTime = DateUtil.convertStringToDate(examingMonitor.getiDCardTime()).getTime();
            if (!SignInType.UnSignIn.getPrefix().equals(idCardResult)
                    && idCardTime >= dateStartTime
                    && idCardTime < dateEndTime ){
                signInStatus = true;
                break;
            }
        }
        if(signInStatus){
            return new OperationResult(OperationResultType.Warning, OperationResultMessage.ALREADY_SIGNED_IN);
        }

        //更新签到
        for (ExamingMonitor examingMonitor : examingeMonitorsList) {
            examingMonitor.setiDCardResult(StringUtils.isEmpty(idCardReason) ? SignInType.Automatic.getPrefix() : SignInType.Manual.getPrefix());
            examingMonitor.setiDCardTime(DateUtil.convertEncryptDateToString(new Date()));
            examingMonitor.setiDCardReason(idCardReason);
            examMoniterMapper.updateSignIn(examingMonitor);
        }

        return new OperationResult();
    }

    public List<Map> autoSignInReturnTemple(String appId, String examSiteId, String planId, String examineeName, String certificateNo){
        List<Map> arrangeList = new ArrayList<>();
        List<ExamineeArrange> retExamineeArrangeList = examineeArrangeMapper.findAutoManualSignInRetEAList(appId,examSiteId,planId,examineeName,certificateNo);
        List<ExamSubject> retExamSubjectList = examineeArrangeMapper.findAutoManualSignInRetESList(appId,examSiteId,planId,examineeName,certificateNo);
        for (int i=0;i < retExamineeArrangeList.size();i++){
            Map<String,Object> map = new HashMap();
            map.put(arrangeKey,retExamineeArrangeList.get(i));
            map.put(subjectKey,retExamSubjectList.get(i));
            arrangeList.add(map);
        }
        return arrangeList;
    }

}
